#ifndef EXERCISES_H_INCLUDED
#define EXERCISES_H_INCLUDED

#include "cekla.h"

/**
 * Feladatok
 */

// 1. feladat:
bool csupa01(const int N) {
    if (N == 0) return 1;
    if (N % 10 >= 2) return 0;
    return csupa01(N/10);
}

//2. feladat:
int osztok(const int szam, const int oszto, const int osztoszam) {
    if (szam == oszto) return osztoszam + 1;
    if (szam % oszto == 0) return osztok(szam, oszto + 1, osztoszam + 1);
    return osztok(szam, oszto + 1, osztoszam);
}

int osztok(const int szam) {
    if (szam == 0) return -1;
    return osztok(szam, 1, 0);
}

// 3. feladat:
int lnkoh(const int A, const int B, const int oszto) {
    if (A % oszto == 0 && B % oszto == 0) return oszto;
    return lnkoh(A, B, oszto-1);
}

int lnko(const int A, const int B) {
    if (A == 0) return (B == 0) ? -1 : B;
    return lnkoh(A, B, A);
}

// 4. feladat:
int lnko2(const int A, const int B) {
    if (A == 0 && B == 0) return -1;
    if (B != 0) return lnko2(B, A % B);
    return A;
}

// 5. feladat:
int length(const list L) {
    if (L == nil) return 0;
    return 1 + length(tl(L));
}

// 5*. feladat:
int length2(const list L, const int Len) {
    if (L == nil) return Len;
    return length2(tl(L), Len + 1);
}

int length2(const list L) {
    return length2(L, 0);
}

// 6. feladat:
list lista_noveltje(const list L) {
    if (L == nil) return nil;
    return cons(hd(L) + 1, lista_noveltje(tl(L)));
}

// 7. feladat:
int last(const list L) {
    if (tl(L) == nil) return hd(L);
    return last(tl(L));
}

// 8. feladat:
list insert_nth(const list L, const int N, const int E) {
    if (L == nil) return cons(E, nil);
    if (N <= 1) return cons(E, L);
    return cons(hd(L), insert_nth(tl(L), N - 1, E));
}

// 9. feladat:
int nth1(const list L, const int N) {
    if (L == nil) return -1;
    if (N == 1) return hd(L);
    return nth1(tl(L), N - 1);
}

// 10. feladat:
list take(const list L, const int H) {
    if (L == nil || H < 1) return nil;
    return cons(hd(L), take(tl(L), H-1));
}

// 11. feladat:
list drop(const list L, const int B) {
    if (L == nil) return nil;
    if (B < 1) return L;//cons(hd(L), drop(tl(L), 0));
    return drop(tl(L), B - 1);
}

// 12. feladat:
list sublist(const list L, const int H, const int B) {
    return take(drop(L, B), H);
}

// 13. feladat:
list parban(const list L) {
    if (L == nil || tl(L) == nil) return nil;
    if (hd(L) == hd(tl(L))) return cons(hd(L), parban(tl(L)));
    return parban(tl(L));
}

// 13*. feladat:
list parban2(const list L) {
    if (L == nil || tl(L) == nil) return nil;
    if (hd(L) == hd(tl(L))) return cons(hd(L), parban2(tl(L)));
    return parban(tl(L));
}

list parban2(const list L, const list eredmeny) {

}

// 14. feladat:
list map(const fun1 F, const list L) {
    if (L == nil) return nil;
    return cons(F(hd(L)), map(F, tl(L)));
}

int listaelem_novelo(const int X) {
    return X + 1;
}

list lista_noveltje2(const list L) {
    return map(listaelem_novelo, L);
}

// 15. feladat
int foldl(const fun2 F, const int Acc, const list L) {
    if (L == nil) return Acc;
    else return foldl(F, F(hd(L), Acc), tl(L));
}

int actindex(int elem, int index) {
    return index + 1;
}

int length3(const list L) {
    return foldl(actindex, 0, L);
}

// 16. feladat
int getelem(int elem, int unneeded) {
    return elem;
}

int last2(const list L) {
    return foldl(getelem, -1, L);
}

// 17. feladat
int sumi(const int A, const int B) {
    return A + B;
}

int sum(const list L) {
    return foldl(sumi, 0, L);
}

// 18. feladat
int sumsqi(const int A, const int B) {
    return A*A + B;
}

int sumsq(const list L) {
    return foldl(sumsqi, 0, L);
}

// 19. feladat
int sq(const int A) {
    return A*A;
}

int sumsq2(const list L) {
    return sum(map(sq, L));
}

#endif // EXERCISES_H_INCLUDED
